home *** CD-ROM | disk | FTP | other *** search
- #include <stdlib.h>
- #include <stdio.h>
- #include <process.h> /* for msvc _beginthreadex, _endthreadex */
- #include <windows.h>
-
- #include "sub_proc.h"
- #include "proc.h"
- #include "w32err.h"
-
- static char *make_command_line( char *shell_name, char *exec_path, char **argv);
-
- typedef struct sub_process_t {
- int sv_stdin[2];
- int sv_stdout[2];
- int sv_stderr[2];
- int using_pipes;
- char *inp;
- DWORD incnt;
- char * volatile outp;
- volatile DWORD outcnt;
- char * volatile errp;
- volatile DWORD errcnt;
- int pid;
- int exit_code;
- int signal;
- long last_err;
- long lerrno;
- } sub_process;
-
- /* keep track of children so we can implement a waitpid-like routine */
- static sub_process *proc_array[256];
- static int proc_index = 0;
- static int fake_exits_pending = 0;
-
- /*
- * When a process has been waited for, adjust the wait state
- * array so that we don't wait for it again
- */
- static void
- process_adjust_wait_state(sub_process* pproc)
- {
- int i;
-
- if (!proc_index)
- return;
-
- for (i = 0; i < proc_index; i++)
- if (proc_array[i]->pid == pproc->pid)
- break;
-
- if (i < proc_index) {
- proc_index--;
- if (i != proc_index)
- memmove(&proc_array[i], &proc_array[i+1],
- (proc_index-i) * sizeof(sub_process*));
- proc_array[proc_index] = NULL;
- }
- }
-
- /*
- * Waits for any of the registered child processes to finish.
- */
- static sub_process *
- process_wait_for_any_private(void)
- {
- HANDLE handles[256];
- DWORD retval, which;
- int i;
-
- if (!proc_index)
- return NULL;
-
- /* build array of handles to wait for */
- for (i = 0; i < proc_index; i++) {
- handles[i] = (HANDLE) proc_array[i]->pid;
-
- if (fake_exits_pending && proc_array[i]->exit_code)
- break;
- }
-
- /* wait for someone to exit */
- if (!fake_exits_pending) {
- retval = WaitForMultipleObjects(proc_index, handles, FALSE, INFINITE);
- which = retval - WAIT_OBJECT_0;
- } else {
- fake_exits_pending--;
- retval = !WAIT_FAILED;
- which = i;
- }
-
- /* return pointer to process */
- if (retval != WAIT_FAILED) {
- sub_process* pproc = proc_array[which];
- process_adjust_wait_state(pproc);
- return pproc;
- } else
- return NULL;
- }
-
- /*
- * Terminate a process.
- */
- BOOL
- process_kill(HANDLE proc, int signal)
- {
- sub_process* pproc = (sub_process*) proc;
- pproc->signal = signal;
- return (TerminateProcess((HANDLE) pproc->pid, signal));
- }
-
- /*
- * Use this function to register processes you wish to wait for by
- * calling process_file_io(NULL) or process_wait_any(). This must be done
- * because it is possible for callers of this library to reuse the same
- * handle for multiple processes launches :-(
- */
- void
- process_register(HANDLE proc)
- {
- proc_array[proc_index++] = (sub_process *) proc;
- }
-
- /*
- * Public function which works kind of like waitpid(). Wait for any
- * of the children to die and return results. To call this function,
- * you must do 1 of things:
- *
- * x = process_easy(...);
- *
- * or
- *
- * x = process_init_fd();
- * process_register(x);
- *
- * or
- *
- * x = process_init();
- * process_register(x);
- *
- * You must NOT then call process_pipe_io() because this function is
- * not capable of handling automatic notification of any child
- * death.
- */
-
- HANDLE
- process_wait_for_any(void)
- {
- sub_process* pproc = process_wait_for_any_private();
-
- if (!pproc)
- return NULL;
- else {
- /*
- * Ouch! can't tell caller if this fails directly. Caller
- * will have to use process_last_err()
- */
- (void) process_file_io(pproc);
- return ((HANDLE) pproc);
- }
- }
-
- long
- process_errno(HANDLE proc)
- {
- return (((sub_process *)proc)->lerrno);
- }
-
- long
- process_signal(HANDLE proc)
- {
- return (((sub_process *)proc)->signal);
- }
-
- long
- process_last_err(HANDLE proc)
- {
- return (((sub_process *)proc)->last_err);
- }
-
- long
- process_exit_code(HANDLE proc)
- {
- return (((sub_process *)proc)->exit_code);
- }
-
- char *
- process_outbuf(HANDLE proc)
- {
- return (((sub_process *)proc)->outp);
- }
-
- char *
- process_errbuf(HANDLE proc)
- {
- return (((sub_process *)proc)->errp);
- }
-
- int
- process_outcnt(HANDLE proc)
- {
- return (((sub_process *)proc)->outcnt);
- }
-
- int
- process_errcnt(HANDLE proc)
- {
- return (((sub_process *)proc)->errcnt);
- }
-
- void
- process_pipes(HANDLE proc, int pipes[3])
- {
- pipes[0] = ((sub_process *)proc)->sv_stdin[0];
- pipes[1] = ((sub_process *)proc)->sv_stdout[0];
- pipes[2] = ((sub_process *)proc)->sv_stderr[0];
- return;
- }
-
-
- HANDLE
- process_init()
- {
- sub_process *pproc;
- /*
- * open file descriptors for attaching stdin/stdout/sterr
- */
- HANDLE stdin_pipes[2];
- HANDLE stdout_pipes[2];
- HANDLE stderr_pipes[2];
- SECURITY_ATTRIBUTES inherit;
- BYTE sd[SECURITY_DESCRIPTOR_MIN_LENGTH];
-
- pproc = malloc(sizeof(*pproc));
- memset(pproc, 0, sizeof(*pproc));
-
- /* We can't use NULL for lpSecurityDescriptor because that
- uses the default security descriptor of the calling process.
- Instead we use a security descriptor with no DACL. This
- allows nonrestricted access to the associated objects. */
-
- if (!InitializeSecurityDescriptor((PSECURITY_DESCRIPTOR)(&sd),
- SECURITY_DESCRIPTOR_REVISION)) {
- pproc->last_err = GetLastError();
- pproc->lerrno = E_SCALL;
- return((HANDLE)pproc);
- }
-
- inherit.nLength = sizeof(inherit);
- inherit.lpSecurityDescriptor = (PSECURITY_DESCRIPTOR)(&sd);
- inherit.bInheritHandle = TRUE;
-
- // By convention, parent gets pipe[0], and child gets pipe[1]
- // This means the READ side of stdin pipe goes into pipe[1]
- // and the WRITE side of the stdout and stderr pipes go into pipe[1]
- if (CreatePipe( &stdin_pipes[1], &stdin_pipes[0], &inherit, 0) == FALSE ||
- CreatePipe( &stdout_pipes[0], &stdout_pipes[1], &inherit, 0) == FALSE ||
- CreatePipe( &stderr_pipes[0], &stderr_pipes[1], &inherit, 0) == FALSE) {
-
- pproc->last_err = GetLastError();
- pproc->lerrno = E_SCALL;
- return((HANDLE)pproc);
- }
-
- //
- // Mark the parent sides of the pipes as non-inheritable
- //
- if (SetHandleInformation(stdin_pipes[0],
- HANDLE_FLAG_INHERIT, 0) == FALSE ||
- SetHandleInformation(stdout_pipes[0],
- HANDLE_FLAG_INHERIT, 0) == FALSE ||
- SetHandleInformation(stderr_pipes[0],
- HANDLE_FLAG_INHERIT, 0) == FALSE) {
-
- pproc->last_err = GetLastError();
- pproc->lerrno = E_SCALL;
- return((HANDLE)pproc);
- }
- pproc->sv_stdin[0] = (int) stdin_pipes[0];
- pproc->sv_stdin[1] = (int) stdin_pipes[1];
- pproc->sv_stdout[0] = (int) stdout_pipes[0];
- pproc->sv_stdout[1] = (int) stdout_pipes[1];
- pproc->sv_stderr[0] = (int) stderr_pipes[0];
- pproc->sv_stderr[1] = (int) stderr_pipes[1];
-
- pproc->using_pipes = 1;
-
- pproc->lerrno = 0;
-
- return((HANDLE)pproc);
- }
-
-
- HANDLE
- process_init_fd(HANDLE stdinh, HANDLE stdouth, HANDLE stderrh)
- {
- sub_process *pproc;
-
- pproc = malloc(sizeof(*pproc));
- memset(pproc, 0, sizeof(*pproc));
-
- /*
- * Just pass the provided file handles to the 'child side' of the
- * pipe, bypassing pipes altogether.
- */
- pproc->sv_stdin[1] = (int) stdinh;
- pproc->sv_stdout[1] = (int) stdouth;
- pproc->sv_stderr[1] = (int) stderrh;
-
- pproc->last_err = pproc->lerrno = 0;
-
- return((HANDLE)pproc);
- }
-
-
- static HANDLE
- find_file(char *exec_path, LPOFSTRUCT file_info)
- {
- HANDLE exec_handle;
- char *fname;
- char *ext;
-
- fname = malloc(strlen(exec_path) + 5);
- strcpy(fname, exec_path);
- ext = fname + strlen(fname);
-
- strcpy(ext, ".exe");
- if ((exec_handle = (HANDLE)OpenFile(fname, file_info,
- OF_READ | OF_SHARE_COMPAT)) != (HANDLE)HFILE_ERROR) {
- free(fname);
- return(exec_handle);
- }
-
- strcpy(ext, ".cmd");
- if ((exec_handle = (HANDLE)OpenFile(fname, file_info,
- OF_READ | OF_SHARE_COMPAT)) != (HANDLE)HFILE_ERROR) {
- free(fname);
- return(exec_handle);
- }
-
- strcpy(ext, ".bat");
- if ((exec_handle = (HANDLE)OpenFile(fname, file_info,
- OF_READ | OF_SHARE_COMPAT)) != (HANDLE)HFILE_ERROR) {
- free(fname);
- return(exec_handle);
- }
-
- /* should .com come before this case? */
- if ((exec_handle = (HANDLE)OpenFile(exec_path, file_info,
- OF_READ | OF_SHARE_COMPAT)) != (HANDLE)HFILE_ERROR) {
- free(fname);
- return(exec_handle);
- }
-
- strcpy(ext, ".com");
- if ((exec_handle = (HANDLE)OpenFile(fname, file_info,
- OF_READ | OF_SHARE_COMPAT)) != (HANDLE)HFILE_ERROR) {
- free(fname);
- return(exec_handle);
- }
-
- free(fname);
- return(exec_handle);
- }
-
-
- /*
- * Description: Create the child process to be helped
- *
- * Returns:
- *
- * Notes/Dependencies:
- */
- long
- process_begin(
- HANDLE proc,
- char **argv,
- char **envp,
- char *exec_path,
- char *as_user)
- {
- sub_process *pproc = (sub_process *)proc;
- char *shell_name = 0;
- int file_not_found=0;
- HANDLE exec_handle;
- char buf[256];
- DWORD bytes_returned;
- DWORD flags;
- char *command_line;
- STARTUPINFO startInfo;
- PROCESS_INFORMATION procInfo;
- char *envblk=NULL;
- OFSTRUCT file_info;
-
-
- /*
- * Shell script detection... if the exec_path starts with #! then
- * we want to exec shell-script-name exec-path, not just exec-path
- * NT doesn't recognize #!/bin/sh or #!/etc/Tivoli/bin/perl. We do not
- * hard-code the path to the shell or perl or whatever: Instead, we
- * assume it's in the path somewhere (generally, the NT tools
- * bin directory)
- * We use OpenFile here because it is capable of searching the Path.
- */
-
- exec_handle = find_file(exec_path, &file_info);
-
- /*
- * If we couldn't open the file, just assume that Windows32 will be able
- * to find and execute it.
- */
- if (exec_handle == (HANDLE)HFILE_ERROR) {
- file_not_found++;
- }
- else {
- /* Attempt to read the first line of the file */
- if (ReadFile( exec_handle,
- buf, sizeof(buf) - 1, /* leave room for trailing NULL */
- &bytes_returned, 0) == FALSE || bytes_returned < 2) {
-
- pproc->last_err = GetLastError();
- pproc->lerrno = E_IO;
- CloseHandle(exec_handle);
- return(-1);
- }
- if (buf[0] == '#' && buf[1] == '!') {
- /*
- * This is a shell script... Change the command line from
- * exec_path args to shell_name exec_path args
- */
- char *p;
-
- /* Make sure buf is NULL terminated */
- buf[bytes_returned] = 0;
- /*
- * Depending on the file system type, etc. the first line
- * of the shell script may end with newline or newline-carriage-return
- * Whatever it ends with, cut it off.
- */
- p= strchr(buf, '\n');
- if (p)
- *p = 0;
- p = strchr(buf, '\r');
- if (p)
- *p = 0;
-
- /*
- * Find base name of shell
- */
- shell_name = strrchr( buf, '/');
- if (shell_name) {
- shell_name++;
- } else {
- shell_name = &buf[2];/* skipping "#!" */
- }
-
- }
- CloseHandle(exec_handle);
- }
-
- flags = 0;
-
- if (file_not_found)
- command_line = make_command_line( shell_name, exec_path, argv);
- else
- command_line = make_command_line( shell_name, file_info.szPathName,
- argv);
-
- if ( command_line == NULL ) {
- pproc->last_err = 0;
- pproc->lerrno = E_NO_MEM;
- return(-1);
- }
-
- if (envp) {
- if (arr2envblk(envp, &envblk) ==FALSE) {
- pproc->last_err = 0;
- pproc->lerrno = E_NO_MEM;
- free( command_line );
- return(-1);
- }
- }
-
- if ((shell_name) || (file_not_found)) {
- exec_path = 0; /* Search for the program in %Path% */
- } else {
- exec_path = file_info.szPathName;
- }
-
- /*
- * Set up inherited stdin, stdout, stderr for child
- */
- GetStartupInfo(&startInfo);
- startInfo.dwFlags = STARTF_USESTDHANDLES;
- startInfo.lpReserved = 0;
- startInfo.cbReserved2 = 0;
- startInfo.lpReserved2 = 0;
- startInfo.lpTitle = shell_name ? shell_name : exec_path;
- startInfo.hStdInput = (HANDLE)pproc->sv_stdin[1];
- startInfo.hStdOutput = (HANDLE)pproc->sv_stdout[1];
- startInfo.hStdError = (HANDLE)pproc->sv_stderr[1];
-
- if (as_user) {
- if (envblk) free(envblk);
- return -1;
- } else {
- if (CreateProcess(
- exec_path,
- command_line,
- NULL,
- 0, /* default security attributes for thread */
- TRUE, /* inherit handles (e.g. helper pipes, oserv socket) */
- flags,
- envblk,
- 0, /* default starting directory */
- &startInfo,
- &procInfo) == FALSE) {
-
- pproc->last_err = GetLastError();
- pproc->lerrno = E_FORK;
- fprintf(stderr, "process_begin: CreateProcess(%s, %s, ...) failed.\n", exec_path, command_line);
- if (envblk) free(envblk);
- free( command_line );
- return(-1);
- }
- }
-
- pproc->pid = (int)procInfo.hProcess;
- /* Close the thread handle -- we'll just watch the process */
- CloseHandle(procInfo.hThread);
-
- /* Close the halves of the pipes we don't need */
- if (pproc->sv_stdin) {
- CloseHandle((HANDLE)pproc->sv_stdin[1]);
- (HANDLE)pproc->sv_stdin[1] = 0;
- }
- if (pproc->sv_stdout) {
- CloseHandle((HANDLE)pproc->sv_stdout[1]);
- (HANDLE)pproc->sv_stdout[1] = 0;
- }
- if (pproc->sv_stderr) {
- CloseHandle((HANDLE)pproc->sv_stderr[1]);
- (HANDLE)pproc->sv_stderr[1] = 0;
- }
-
- free( command_line );
- if (envblk) free(envblk);
- pproc->lerrno=0;
- return 0;
- }
-
-
-
- static DWORD
- proc_stdin_thread(sub_process *pproc)
- {
- DWORD in_done;
- for (;;) {
- if (WriteFile( (HANDLE) pproc->sv_stdin[0], pproc->inp, pproc->incnt,
- &in_done, NULL) == FALSE)
- _endthreadex(0);
- // This if should never be true for anonymous pipes, but gives
- // us a chance to change I/O mechanisms later
- if (in_done < pproc->incnt) {
- pproc->incnt -= in_done;
- pproc->inp += in_done;
- } else {
- _endthreadex(0);
- }
- }
- return 0; // for compiler warnings only.. not reached
- }
-
- static DWORD
- proc_stdout_thread(sub_process *pproc)
- {
- DWORD bufsize = 1024;
- char c;
- DWORD nread;
- pproc->outp = malloc(bufsize);
- if (pproc->outp == NULL)
- _endthreadex(0);
- pproc->outcnt = 0;
-
- for (;;) {
- if (ReadFile( (HANDLE)pproc->sv_stdout[0], &c, 1, &nread, NULL)
- == FALSE) {
- /* map_windows32_error_to_string(GetLastError());*/
- _endthreadex(0);
- }
- if (nread == 0)
- _endthreadex(0);
- if (pproc->outcnt + nread > bufsize) {
- bufsize += nread + 512;
- pproc->outp = realloc(pproc->outp, bufsize);
- if (pproc->outp == NULL) {
- pproc->outcnt = 0;
- _endthreadex(0);
- }
- }
- pproc->outp[pproc->outcnt++] = c;
- }
- return 0;
- }
-
- static DWORD
- proc_stderr_thread(sub_process *pproc)
- {
- DWORD bufsize = 1024;
- char c;
- DWORD nread;
- pproc->errp = malloc(bufsize);
- if (pproc->errp == NULL)
- _endthreadex(0);
- pproc->errcnt = 0;
-
- for (;;) {
- if (ReadFile( (HANDLE)pproc->sv_stderr[0], &c, 1, &nread, NULL) == FALSE) {
- map_windows32_error_to_string(GetLastError());
- _endthreadex(0);
- }
- if (nread == 0)
- _endthreadex(0);
- if (pproc->errcnt + nread > bufsize) {
- bufsize += nread + 512;
- pproc->errp = realloc(pproc->errp, bufsize);
- if (pproc->errp == NULL) {
- pproc->errcnt = 0;
- _endthreadex(0);
- }
- }
- pproc->errp[pproc->errcnt++] = c;
- }
- return 0;
- }
-
-
- /*
- * Purpose: collects output from child process and returns results
- *
- * Description:
- *
- * Returns:
- *
- * Notes/Dependencies:
- */
- long
- process_pipe_io(
- HANDLE proc,
- char *stdin_data,
- int stdin_data_len)
- {
- sub_process *pproc = (sub_process *)proc;
- bool_t stdin_eof = FALSE, stdout_eof = FALSE, stderr_eof = FALSE;
- HANDLE childhand = (HANDLE) pproc->pid;
- HANDLE tStdin, tStdout, tStderr;
- DWORD dwStdin, dwStdout, dwStderr;
- HANDLE wait_list[4];
- DWORD wait_count;
- DWORD wait_return;
- HANDLE ready_hand;
- bool_t child_dead = FALSE;
-
-
- /*
- * Create stdin thread, if needed
- */
- pproc->inp = stdin_data;
- pproc->incnt = stdin_data_len;
- if (!pproc->inp) {
- stdin_eof = TRUE;
- CloseHandle((HANDLE)pproc->sv_stdin[0]);
- (HANDLE)pproc->sv_stdin[0] = 0;
- } else {
- tStdin = (HANDLE) _beginthreadex( 0, 1024,
- (unsigned (__stdcall *) (void *))proc_stdin_thread, pproc, 0,
- (unsigned int *) &dwStdin);
- if (tStdin == 0) {
- pproc->last_err = GetLastError();
- pproc->lerrno = E_SCALL;
- goto done;
- }
- }
-
- /*
- * Assume child will produce stdout and stderr
- */
- tStdout = (HANDLE) _beginthreadex( 0, 1024,
- (unsigned (__stdcall *) (void *))proc_stdout_thread, pproc, 0,
- (unsigned int *) &dwStdout);
- tStderr = (HANDLE) _beginthreadex( 0, 1024,
- (unsigned (__stdcall *) (void *))proc_stderr_thread, pproc, 0,
- (unsigned int *) &dwStderr);
-
- if (tStdout == 0 || tStderr == 0) {
-
- pproc->last_err = GetLastError();
- pproc->lerrno = E_SCALL;
- goto done;
- }
-
-
- /*
- * Wait for all I/O to finish and for the child process to exit
- */
-
- while (!stdin_eof || !stdout_eof || !stderr_eof || !child_dead) {
- wait_count = 0;
- if (!stdin_eof) {
- wait_list[wait_count++] = tStdin;
- }
- if (!stdout_eof) {
- wait_list[wait_count++] = tStdout;
- }
- if (!stderr_eof) {
- wait_list[wait_count++] = tStderr;
- }
- if (!child_dead) {
- wait_list[wait_count++] = childhand;
- }
-
- wait_return = WaitForMultipleObjects(wait_count, wait_list,
- FALSE, /* don't wait for all: one ready will do */
- child_dead? 1000 :INFINITE); /* after the child dies, subthreads have
- one second to collect all remaining output */
-
- if (wait_return == WAIT_FAILED) {
- /* map_windows32_error_to_string(GetLastError());*/
- pproc->last_err = GetLastError();
- pproc->lerrno = E_SCALL;
- goto done;
- }
-
- ready_hand = wait_list[wait_return - WAIT_OBJECT_0];
-
- if (ready_hand == tStdin) {
- CloseHandle((HANDLE)pproc->sv_stdin[0]);
- (HANDLE)pproc->sv_stdin[0] = 0;
- CloseHandle(tStdin);
- tStdin = 0;
- stdin_eof = TRUE;
-
- } else if (ready_hand == tStdout) {
-
- CloseHandle((HANDLE)pproc->sv_stdout[0]);
- (HANDLE)pproc->sv_stdout[0] = 0;
- CloseHandle(tStdout);
- tStdout = 0;
- stdout_eof = TRUE;
-
- } else if (ready_hand == tStderr) {
-
- CloseHandle((HANDLE)pproc->sv_stderr[0]);
- (HANDLE)pproc->sv_stderr[0] = 0;
- CloseHandle(tStderr);
- tStderr = 0;
- stderr_eof = TRUE;
-
- } else if (ready_hand == childhand) {
-
- if (GetExitCodeProcess(childhand, &pproc->exit_code) == FALSE) {
- pproc->last_err = GetLastError();
- pproc->lerrno = E_SCALL;
- goto done;
- }
- child_dead = TRUE;
-
- } else {
-
- /* ?? Got back a handle we didn't query ?? */
- pproc->last_err = 0;
- pproc->lerrno = E_FAIL;
- goto done;
- }
- }
-
- done:
- if (tStdin != 0)
- CloseHandle(tStdin);
- if (tStdout != 0)
- CloseHandle(tStdout);
- if (tStderr != 0)
- CloseHandle(tStderr);
-
- if (pproc->lerrno)
- return(-1);
- else
- return(0);
-
- }
-
- /*
- * Purpose: collects output from child process and returns results
- *
- * Description:
- *
- * Returns:
- *
- * Notes/Dependencies:
- */
- long
- process_file_io(
- HANDLE proc)
- {
- sub_process *pproc;
- HANDLE childhand;
- DWORD wait_return;
-
- if (proc == NULL)
- pproc = process_wait_for_any_private();
- else
- pproc = (sub_process *)proc;
-
- /* some sort of internal error */
- if (!pproc)
- return -1;
-
- childhand = (HANDLE) pproc->pid;
-
- /*
- * This function is poorly named, and could also be used just to wait
- * for child death if you're doing your own pipe I/O. If that is
- * the case, close the pipe handles here.
- */
- if (pproc->sv_stdin[0]) {
- CloseHandle((HANDLE)pproc->sv_stdin[0]);
- pproc->sv_stdin[0] = 0;
- }
- if (pproc->sv_stdout[0]) {
- CloseHandle((HANDLE)pproc->sv_stdout[0]);
- pproc->sv_stdout[0] = 0;
- }
- if (pproc->sv_stderr[0]) {
- CloseHandle((HANDLE)pproc->sv_stderr[0]);
- pproc->sv_stderr[0] = 0;
- }
-
- /*
- * Wait for the child process to exit
- */
-
- wait_return = WaitForSingleObject(childhand, INFINITE);
-
- if (wait_return != WAIT_OBJECT_0) {
- /* map_windows32_error_to_string(GetLastError());*/
- pproc->last_err = GetLastError();
- pproc->lerrno = E_SCALL;
- goto done2;
- }
-
- if (GetExitCodeProcess(childhand, &pproc->exit_code) == FALSE) {
- pproc->last_err = GetLastError();
- pproc->lerrno = E_SCALL;
- }
-
- done2:
- if (pproc->lerrno)
- return(-1);
- else
- return(0);
-
- }
-
- /*
- * Description: Clean up any leftover handles, etc. It is up to the
- * caller to manage and free the input, ouput, and stderr buffers.
- */
- void
- process_cleanup(
- HANDLE proc)
- {
- sub_process *pproc = (sub_process *)proc;
- int i;
-
- if (pproc->using_pipes) {
- for (i= 0; i <= 1; i++) {
- if ((HANDLE)pproc->sv_stdin[i])
- CloseHandle((HANDLE)pproc->sv_stdin[i]);
- if ((HANDLE)pproc->sv_stdout[i])
- CloseHandle((HANDLE)pproc->sv_stdout[i]);
- if ((HANDLE)pproc->sv_stderr[i])
- CloseHandle((HANDLE)pproc->sv_stderr[i]);
- }
- }
- if ((HANDLE)pproc->pid)
- CloseHandle((HANDLE)pproc->pid);
-
- free(pproc);
- }
-
-
- /*
- * Try to protect against WINDOWS32 argument munging. This function takes
- * an argv vector and outputs a 'protected' string as a return
- * value. The return code can be safely passed to CreateProcess().
- *
- * The caller should free the return value.
- */
-
- #define TRACE(x)
- static char *fix_command_line(char *args[])
- {
- int i;
- char *narg;
- char *nargp;
- char *p;
- char *q;
- int alloc_len = 0;
-
- for (i = 0; args[i]; i++)
- alloc_len += ((strlen(args[i]) * 2) + 1);
- /* account for possible enclosing quotes and null termination */
- alloc_len += 3;
-
- nargp = narg = malloc(alloc_len);
-
- for (i = 0; args[i]; i++) {
- p = args[i];
- TRACE(("original arg: %s\n", p));
-
- if (*p == '\0') {
- *nargp++ = '"';
- *nargp++ = '"';
- *nargp = '\0';
- TRACE(("empty string arg: %s\n", nargp-2));
- } else if (strpbrk(p, "\" \t")) {
- /* point to end of copy buffer */
- q = narg;
- q += (alloc_len-1);
- *q-- = '\0'; /* ensure null terminated string */
- *q-- = '"'; /* terminating quote of argument */
-
- /* point to end of the input string */
- p = args[i];
- p += strlen(args[i]);
- p--;
-
- /*
- * Because arg is quoted, escape any backslashes
- * that might occur at the end of the string which
- * proceed the closing quote.
- * Example:
- * foo c:\
- * Becomes:
- * "foo c:\\"
- */
- while (*p == '\\')
- *q-- = *p--, *q-- = '\\';
-
- /* copy the string in reverse */
- while (p >= args[i]) {
- /* copy the character */
- *q-- = *p--;
-
- /*
- * Escape any double quote found. Also escape
- * each backslash preceding the double quote.
- */
- if (*(p+1) == '"') {
- *q-- = '\\';
- if (p >= args[i] && *p == '\\')
- while (p >= args[i] && *p == '\\')
- *q-- = *p--, *q-- = '\\';
- }
- }
-
- /* finish quoting arg, q now points to complete arg */
- *q = '"';
-
- /* rejustify */
- memmove(nargp, q, strlen(q) + 1);
- TRACE(("arg with white space or doublequotes: %s\n", nargp));
- nargp += strlen(nargp);
- } else {
- /* just copy the argument, no protection needed */
- strcpy(nargp, args[i]);
- TRACE(("plain arg: %s\n", nargp));
- nargp += strlen(nargp);
- }
-
- /* separate arguments with spaces (if more args to gather) */
- if (args[i+1])
- *nargp++ = ' ';
- *nargp = '\0';
- } /* end for */
-
- /* NULL terminate the arg list */
- *nargp = '\0';
-
- return (narg);
- }
- #undef TRACE
-
- /*
- * Description:
- * Create a command line buffer to pass to CreateProcess
- *
- * Returns: the buffer or NULL for failure
- * Shell case: sh_name a:/full/path/to/script argv[1] argv[2] ...
- * Otherwise: argv[0] argv[1] argv[2] ...
- *
- * Notes/Dependencies:
- * CreateProcess does not take an argv, so this command creates a
- * command line for the executable.
- */
-
- static char *
- make_command_line( char *shell_name, char *exec_path, char **argv)
- {
- char** nargv;
- char* buf;
- int i;
- char** shargv = NULL;
- char* p = NULL;
- char* q = NULL;
- int j = 0;
-
- if (shell_name) {
- /* handle things like: #!/bin/sh -x */
-
- /* count tokens */
- q = strdup(shell_name);
- for (j = 0, p = q; (p = strtok(p, " \t")) != NULL; p = NULL, j++);
- free(q);
-
- /* copy tokens */
- q = strdup(shell_name);
- shargv = (char **) malloc((j+1) * sizeof (char *));
- for (j = 0, p = q; (p = strtok(p, " \t")) != NULL; p = NULL, j++)
- shargv[j] = strdup(p);
- shargv[j] = NULL;
- free(q);
-
- /* create argv */
- for (i = 0; argv[i]; i++);
- i += (j+1);
- nargv = (char **) malloc(i * sizeof (char *));
- for (i = 0; shargv[i] != NULL; i++)
- nargv[i] = shargv[i];
- for (j = 0; argv[j]; j++, i++)
- nargv[i] = argv[j];
- nargv[i] = NULL;
- } else
- nargv = argv;
-
- /* create string suitable for CreateProcess() */
- buf = fix_command_line(nargv);
-
- if (shell_name) {
- for (j = 0; shargv[j]; j++)
- free(shargv[j]);
- free(shargv);
- free(nargv);
- }
-
- return buf;
- }
-
- /*
- * Description: Given an argv and optional envp, launch the process
- * using the default stdin, stdout, and stderr handles.
- * Also, register process so that process_wait_for_any_private()
- * can be used via process_file_io(NULL) or
- * process_wait_for_any().
- *
- * Returns:
- *
- * Notes/Dependencies:
- */
- HANDLE
- process_easy(
- char **argv,
- char **envp)
- {
- HANDLE hIn;
- HANDLE hOut;
- HANDLE hErr;
- HANDLE hProcess;
-
- if (DuplicateHandle(GetCurrentProcess(),
- GetStdHandle(STD_INPUT_HANDLE),
- GetCurrentProcess(),
- &hIn,
- 0,
- TRUE,
- DUPLICATE_SAME_ACCESS) == FALSE) {
- fprintf(stderr,
- "process_easy: DuplicateHandle(In) failed (e=%d)\n",
- GetLastError());
- return INVALID_HANDLE_VALUE;
- }
- if (DuplicateHandle(GetCurrentProcess(),
- GetStdHandle(STD_OUTPUT_HANDLE),
- GetCurrentProcess(),
- &hOut,
- 0,
- TRUE,
- DUPLICATE_SAME_ACCESS) == FALSE) {
- fprintf(stderr,
- "process_easy: DuplicateHandle(Out) failed (e=%d)\n",
- GetLastError());
- return INVALID_HANDLE_VALUE;
- }
- if (DuplicateHandle(GetCurrentProcess(),
- GetStdHandle(STD_ERROR_HANDLE),
- GetCurrentProcess(),
- &hErr,
- 0,
- TRUE,
- DUPLICATE_SAME_ACCESS) == FALSE) {
- fprintf(stderr,
- "process_easy: DuplicateHandle(Err) failed (e=%d)\n",
- GetLastError());
- return INVALID_HANDLE_VALUE;
- }
-
- hProcess = process_init_fd(hIn, hOut, hErr);
-
- if (process_begin(hProcess, argv, envp, argv[0], NULL)) {
- fake_exits_pending++;
- ((sub_process*) hProcess)->exit_code = process_last_err(hProcess);
-
- /* close up unused handles */
- CloseHandle(hIn);
- CloseHandle(hOut);
- CloseHandle(hErr);
- }
-
- process_register(hProcess);
-
- return hProcess;
- }
-